import pagination from "../index.json";
export { pagination };

# Rollup-Web 架构

Rollup-Web 不单单只是 Rollup 的浏览器版本，它还对 Worker、 iframe 环境进行了适配，提供了一整套服务于浏览器的 plugins，可以实现一体化的文件打包执行。

## Rollup-Web

<Embed src="/doc/zh_cn/Guide/assets/implementation.drawio" autoheight></Embed>

## 执行线程的设计

Rollup-Web 提供了直接初始化执行线程的方式。执行线程的任务就是将初始 URL 请求打包线程打包，执行返回的代码，并在执行后进行依赖代码打包请求。在 Rollup-Web 中我们使用的接口是 `Evaluator`。

> 执行线程可以有多种宿主环境： 主线程`可以操作 DOM`，Worker 线程`在源代码中创建了 Worker`、Iframe 线程

1. **执行环境的预准备**`createEnv`：根据执行环境的不同，我们将调节 Worker 和 Iframe 将一些全局属性定义为正确的参数。

2. **模块解析**`import`：代码执行环境引入了 systemjs 进行模块操作，我们对其进行了一系列定制，使得它的模块请求转接到打包线程或者直接进行 ESM 的加载。

3. **请求代码打包**`import`：将相对路径的 URL 转化为绝对路径，并交由打包线程进行操作。

4. **执行打包代码**`import`：根据执行环境的不同，我们需要对打包代码的模块内的全局变量进行复写，以保证正确的 location 等变量，然后进行代码执行。

## 打包线程的设计

Rollup-Web 打包线程是专门为打包复杂代码所开设的线程，这个线程是服务线程，通过提供打包服务为执行线程提供可执行代码。这个线程接收 URL、负责下载并解析文件、转化文件为可执行文件。

> 注意，原本 Rollup 打包可以直接依赖解析并打包多个文件，但是我们为了缓存效果和模块替换考虑，直接采用了单个文件的转化，并没有进行模块依赖解析。依赖解析这个部分交由 Evaluator 进行管理。

1. 接收 URL： 这个 URL 必须为绝对地址，在后面会被用于下载文件和标识文件。

2. 下载文件：下载文件本身为 Rollup 的一个插件，可以通过 Fetcher 进行本地文件载入。

3. 转化文件为可执行代码：简单来说就是使用众多的 Rollup 插件转化为 systemjs 可执行代码。

4. 返回可执行代码：通过 Comlink 构建的代码桥，我们将可执行代码通过端口交回执行线程。

## Rollup 插件设计

Rollup-Web 没有像 Vite 一样包装 Rollup 的插件，我们直接采用了 Rollup 的插件机制，并在此之上进行各种转化操作。所以，那你会编写 Rollup 插件，就会编写 Rollup-Web 插件。

> Rollup-Web 的插件很多时候是转化某些文件为可执行文件的，所以，不需要太多的 Nodejs api。（如 replace、json、commonjs 等）
>
> 小知识：当插件本身没有涉及到太多 Nodejs 的原生功能的时候，可以直接在浏览器端使用 ESM.sh 获取！

## 文件管理设计

### 源代码文件存储

Rollup-Web 采用了唯一的 URL 对应源代码的形式进行资源管理。同时，我们采用了可替换的源代码获取方式（代码名称为 Fetcher），所以可以适配多种不同的应用场景。

### 多级缓存设计

我们在 Rollup-Web 系统中提供了缓存机制来保证部署展示时速度超级快。浏览器本身对于文件具有强缓存，在其上，我们制作了一个插件管理系统，保证我们的文件访问速度。

#### 缓存层级

<Embed src="/doc/zh_cn/Guide/assets/CacheSystem.drawio" autoheight></Embed>

1. Memory Cache：即时缓存，即当直接向底层进行网络请求时，我们进行了 JS 的内存缓存，文件都在 Compiler 线程。

2. Local Cache： 本地缓存机制的主要底层为 IndexDB，我们使用了 localforage 这个库进行便捷的操作。这个缓存是持久的，但是需要手动开启。

3. Browser Cache：如果上面两层缓存失效，导致 Compiler 线程需要请求 CDN Module，那么会触发浏览器的强缓存，文件将会在几十毫秒内传入 Compiler。

4. Remote Services：如果三层缓存失效，那么将会直接请求服务器进行源代码下载，速度就取决于服务器响应了。

#### 缓存种类

1. ExtensionsCache：后缀名缓存，Nodejs 中可以使用无后缀名的默认写法，但是 ESM 不行，所以需要后缀名自动识别。

2. ModuleCache: 模块缓存，缓存打包后的代码，再次打包时直接获取并使用。

### 模块文件下载

对于原本应该处于 node_modules 中对应的模块，这些年已经有 CDN 在进行 ESM 打包服务了，所以我们需要的是直接更改模块裸导入为 CDN 提供的 URL！这种解决方案我们称之为 **CDN Module**。就像是 Deno 一样，我们也可以在浏览器直接使用 url 作为模块路径。

这里介绍一些可以进行 ESM 打包的 CDN 提供商。

1. [Skypack](https://cdn.skypack.dev)：Skypack 是基于 snowpack 进行打包的一个老牌 CDN Module 提供商，能够高效地打包多数 ESM 代码，所以我们推荐的 CDN 仍然是它。

2. [ESM.run](https://www.jsdelivr.com/esm)：这是 jsdelivr 新创建的项目，可以在浏览器端直接采用 CDN Module，其底层机制为 Rollup 打包源代码，项目仍然处于 Development，所以对于某些代码的编译效果不太好。

3. [ESM.sh](https://esm.sh/)：底层采用 ESBuild 进行打包，所以对于一些 Nodejs 的功能会做补充，使得库在浏览器环境可以被使用。这个网站本来是提供 Deno 的插件的，Deno 的实现目标是浏览器环境，所以大部分都可以使用。

> (babel 的一系列插件就是通过这个 CDN 导入的! )
